package pl.edu.agh.neuraleconomy.dataimporter;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import pl.edu.agh.neuraleconomy.common.utils.DateUtils;
import pl.edu.agh.neuraleconomy.model.exchange.Exchange;
import pl.edu.agh.neuraleconomy.persistence.base.DaoProvider;
import pl.edu.agh.neuraleconomy.persistence.exchange.CompanyDao;
import pl.edu.agh.neuraleconomy.persistence.exchange.CurrencyDao;
import pl.edu.agh.neuraleconomy.persistence.exchange.ExchangeDao;
import pl.edu.agh.neuraleconomy.persistence.utils.DBUtils;

import com.j256.ormlite.misc.TransactionManager;

public class HTMLImporter {
	private Logger logger = Logger.getLogger(getClass());
	private static final String urlFormat = "http://www.gpw.pl/notowania_archiwalne_full?type=10&date=%s";
	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
	private ExchangeDao exchangeDao = DaoProvider.getExchangeDao();
	private CompanyDao companyDao = DaoProvider.getCompanyDao();
	private CurrencyDao currencyDao = DaoProvider.getCurrencyDao();

	private static final String TABLE_CLASS_NAME = "tab03";

	public void importData(Date from, Date to) {
		while (from.compareTo(to) <= 0) {
			importForDate(from);
			from = DateUtils.addDays(from, 1);
		}
	}

	public void importForDate(Date date) {
		try {
			logger.info("Pobieram dane historyczne dla " + dateFormat.format(date));
			Document doc = Jsoup.parse(getHtml(date));
			Element tab = doc.getElementsByClass(TABLE_CLASS_NAME).first();
			if (tab == null) {
				logger.warn(String.format("Brak danych historycznych dla %s. Prawdopodobnie dzien swiateczny.", dateFormat.format(date)));
				return;
			}
			
			final Elements rows = tab.select("tr");
			final Date finalDate = (Date) date.clone();
			
			TransactionManager.callInTransaction(DBUtils.getConnectionSource(), new Callable<Void>() {

				public Void call() throws Exception {
					processRows(rows, finalDate);
					return null;
				}
			});

			
		} catch (Exception e) {
			logger.error("Nie udalo sie sparsowac arkusza", e);
		}
	}
	
	private void processRows(Elements rows, Date date){
		for (int i = 1; i < rows.size(); i++) {
			proccessRow(rows.get(i), date);
		}
	}

	private void proccessRow(Element row, Date date) {
		Elements colls = row.select("td");
		Exchange e = new Exchange();
		e.setDate(date);
		e.setCompany(companyDao.getByNameOrCreate(getText(colls.get(0))));
		e.setCurrency(currencyDao.getByNameOrCreate(getText(colls.get(2))));
		e.setOpeningPrice(getNumericValue(getNumber(colls.get(3))));
		e.setMaxPrice(getNumericValue(getNumber(colls.get(4))));
		e.setMinPrice(getNumericValue(getNumber(colls.get(5))));
		e.setClosingPrice(getNumericValue(getNumber(colls.get(6))));
		e.setTransactions(getNumericValue(getNumber(colls.get(9))).intValue());
		e.setTurnover(getNumericValue(getNumber(colls.get(10))));
		exchangeDao.create(e);
	}

	private BigDecimal getNumericValue(String value) {
		try {
			return new BigDecimal(value);
		} catch (NumberFormatException e) {
			logger.error("Nie udalo sie sparsowac numeru: " + value);
			throw e;
		}
	}
	
	private String getText(Element elem){
		return elem.text().trim();
	}

	private String getNumber(Element elem) {
		String res = elem.text().replaceAll("\\s", "").replace(",", ".").trim();
		String [] splitted = res.split("\\.");
		String head = splitted[0].replaceAll("\\W", "");
		return splitted.length == 2 ? head.concat(".").concat(splitted[1]) : head;
	}

	private String getHtml(Date date) throws Exception {
		BufferedReader in = null;
		InputStream is = null;
		try {
			URL urlPath = new URL(String.format(urlFormat, dateFormat.format(date)));
			URLConnection conn = urlPath.openConnection();
			is = conn.getInputStream();
			in = new BufferedReader(new InputStreamReader(is));
			
			StringWriter writer = new StringWriter();
			IOUtils.copy(in, writer);
			return writer.toString();
			
//			String inputLine;
//			StringBuffer buff = new StringBuffer();
//			while ((inputLine = in.readLine()) != null) {
//				buff.append(inputLine);
//			}
//			return buff.toString();
		} finally {
			IOUtils.closeQuietly(in);
			IOUtils.closeQuietly(is);
		}
	}
}
